﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

using RedLockNet;

namespace Jack.RedisLib
{
    public class MultiRedisLock : IMultiRedisLock, IDisposable, IAsyncDisposable
    {
        private readonly List<IRedLock> redLocks = [];
        private readonly HashSet<string> resources = [];
        private readonly IRedisLock redisLock;

        public MultiRedisLock(IRedisLock redisLock)
        {
            this.redisLock = redisLock;
        }

        /// <summary>
        /// 添加红锁（锁定资源重复时，会返回空）
        /// </summary>
        /// <param name="resource">锁定的资源标识</param>
        /// <param name="expireTime">锁的过期时间（防止锁未释放，导致死锁）</param>
        /// <returns>红锁</returns>
        public async Task<IRedLock> AddLockAsync(string resource, TimeSpan expireTime)
        {
            if (resources.Add(resource) == false) return default;

            var redLock = await redisLock.CreateLockAsync(resource, expireTime);
            redLocks.Add(redLock);
            return redLock;
        }

        /// <summary>
        /// 创建红锁（不加实例前缀；锁定资源重复时，会返回空）
        /// </summary>
        /// <param name="resource">锁定的资源标识</param>
        /// <param name="expireTime">锁的过期时间（防止锁未释放，导致死锁）</param>
        /// <returns>红锁</returns>
        public async Task<IRedLock> AddLockWithoutPrefixAsync(string resource, TimeSpan expireTime)
        {
            if (resources.Add(resource) == false) return default;

            var redLock = await redisLock.CreateLockWithoutPrefixAsync(resource, expireTime);
            redLocks.Add(redLock);
            return redLock;
        }

        /// <summary>
        /// 获取锁成功
        /// </summary>
        public bool IsAcquired => redLocks.Count > 0 && redLocks.All(x => x.IsAcquired);

        public void Dispose()
        {
            if (redLocks.Count == 0) return;
            foreach (var redLock in redLocks)
            {
                redLock.Dispose();
            }
            redLocks.Clear();
        }

        public async ValueTask DisposeAsync()
        {
            if (redLocks.Count == 0) return;
            foreach (var redLock in redLocks)
            {
                await redLock.DisposeAsync();
            }
            redLocks.Clear();
        }
    }
}
